import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';
import { Observable } from 'rxjs';
import { PERMISSION_KEY } from '../decorators/role-permission.decorator';
import { UserRepository } from '@/examples/user/user.repository';
import { RoleService } from '@/examples/role/role.service';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class RolePermissionGuard extends AuthGuard('jwt') {

  constructor(
    private reflector: Reflector, 
    private userRepository: UserRepository, 
    private roleService: RoleService,
    private configService: ConfigService,
  ) {
    super();
  }

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const classPermission = this.reflector.get(PERMISSION_KEY, context.getHandler());
    const handlerPermission = this.reflector.get(PERMISSION_KEY, context.getHandler());
    const cls = classPermission instanceof Array ? classPermission.join('') : classPermission;
    const handler = handlerPermission instanceof Array ? handlerPermission.join('') : handlerPermission;
    const right = `${cls}:${handler}}`;
    const req = context.switchToHttp().getRequest();
    const { name } = req.user;
    const user = await this.userRepository.findOne(name);
    if (!user) {
      return false;
    }

    const roleIds = user.UserRole.map(o => o.roleId);
    // 如果是白名单的用户对应的roleId，应该返回true
    const whitelist = this.configService.get('ROLE_ID_WHITELIST');

    if(whitelist) {
      const whitelistArr = whitelist.split(',');
      // 判断白名单里面的数据
      if(whitelistArr.some(o => roleIds.includes(parseInt(o)))) {
        return true;
      }
    }
    

    const permissions = await this.roleService.findAllByIds(user.UserRole.map(r => r.roleId));
    const permissionsArr = permissions
      .map(p => p.RolePermissions.map(o => o.permission.name))
      .reduce((acc, cur) => {
          // 去重
          return [...new Set([...acc, ...cur])];
      }, []);
    return permissionsArr.some(o => o === right);
  }

}
